Skip to content

MCP Servers

MCP (Model Context Protocol) allows you to connect external tool servers to your agent. MCP servers run as separate processes and expose tools over a standardized protocol.

What is MCP?

MCP is a protocol for connecting AI agents to external tools. Instead of writing C# code for each integration, you can:

  • Use existing MCP servers (filesystem, GitHub, databases, etc.)
  • Connect to any MCP-compatible server
  • Get automatic tool discovery
Agent  ←──MCP Protocol──→  MCP Server (filesystem)
       ←──MCP Protocol──→  MCP Server (github)
       ←──MCP Protocol──→  MCP Server (database)

Quick Start

1. Create a Manifest File

Create MCP.json:

json
{
  "servers": [
    {
      "name": "filesystem",
      "command": "npx",
      "arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
      "description": "File operations within workspace",
      "enabled": true
    }
  ]
}

2. Register with AgentBuilder

csharp
var agent = await new AgentBuilder()
    .WithMCP("./MCP.json")
    .Build();

That's it! The agent now has access to all tools from the filesystem MCP server.


Manifest Configuration

MCPServerConfig Properties

PropertyTypeDefaultDescription
namestringrequiredUnique identifier for the server
commandstringrequiredCommand to start the server
argumentsstring[][]Command arguments
descriptionstringnullDescription shown when collapsed
enabledbooltrueWhether to load this server
enablecollapsingboolnullGroup tools under a container
requiresPermissionbooltrueRequire user approval for tools
functionResultstringnullOne-time message on expansion (appended to auto-generated)
systemPromptstringnullPersistent instructions (injected into system prompt)
timeoutint30000Connection timeout in ms
retryAttemptsint3Number of retry attempts
environmentobjectnullEnvironment variables

Full Example

json
{
  "servers": [
    {
      "name": "filesystem",
      "command": "npx",
      "arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
      "description": "File operations within workspace",
      "enabled": true,
      "enablecollapsing": true,
      "requiresPermission": true,
      "functionResult": "Working directory: /workspace",
      "systemPrompt": "Never write outside /workspace. Always use absolute paths.",
      "timeout": 30000,
      "retryAttempts": 3,
      "environment": {
        "NODE_ENV": "production"
      }
    },
    {
      "name": "github",
      "command": "npx",
      "arguments": ["-y", "@anthropic/mcp-github"],
      "description": "GitHub repository operations",
      "enabled": true,
      "enablecollapsing": true,
      "systemPrompt": "Use search before listing all PRs. Always include PR descriptions.",
      "environment": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  ]
}

Registration Methods

From Manifest File

csharp
var agent = await new AgentBuilder()
    .WithMCP("./MCP.json")
    .Build();

With Options

csharp
var agent = await new AgentBuilder()
    .WithMCP("./MCP.json", options =>
    {
        options.FailOnServerError = false;      // Continue if a server fails
        options.ConnectionTimeout = TimeSpan.FromSeconds(30);
        options.MaxConcurrentServers = 10;
    })
    .Build();

From JSON String

csharp
var manifest = @"{
  ""servers"": [
    {
      ""name"": ""filesystem"",
      ""command"": ""npx"",
      ""arguments"": [""-y"", ""@anthropic/mcp-filesystem""]
    }
  ]
}";

var agent = await new AgentBuilder()
    .WithMCPContent(manifest)
    .Build();

Collapsing

When enablecollapsing is true, all tools from a server are grouped under a container:

Before expansion:           After expansion:
┌─────────────────────┐     ┌─────────────────────┐
│ MCP_filesystem      │ ──► │ read_file           │
│ (5 functions)       │     │ write_file          │
└─────────────────────┘     │ list_directory      │
                            │ create_directory    │
                            │ delete_file         │
                            └─────────────────────┘

Container Naming

Containers are named MCP_{serverName}:

  • filesystemMCP_filesystem
  • githubMCP_github

Enable Collapsing

In manifest:

json
{
  "name": "filesystem",
  "enablecollapsing": true,
  "description": "File operations"
}

The description appears in the container's tool definition.


Server Instructions

MCP servers support the same dual-context architecture as C# tools and Client tools:

ParameterLocationLifetimeUse For
functionResultConversation historyOne-time on expansionAdditional context (appended to auto-generated message)
systemPromptSystem promptEvery turn while expandedCritical rules, workflow

** Requires Collapsing:** functionResult and systemPrompt only work when enablecollapsing: true. If collapsing is disabled, instructions are ignored and validation will fail.

Important: The system automatically generates a base expansion message:

"{serverName} server expanded. Available functions: {FunctionList}"

Your functionResult is appended to this auto-generated message. Don't duplicate the expansion info—use it only for additional context. Pass null if the auto-generated message is sufficient.

json
{
  "name": "filesystem",
  "command": "npx",
  "arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
  "description": "File operations within workspace",
  "enablecollapsing": true,
  "functionResult": "Working directory: /workspace",
  "systemPrompt": "Never write outside /workspace. Always use absolute paths."
}

Via AgentConfig (Legacy)

You can also provide instructions via MCPServerInstructions in AgentConfig. These are injected as SystemPrompt (persistent):

csharp
var config = new AgentConfig
{
    Collapsing = new CollapsingConfig
    {
        MCPServerInstructions = new Dictionary<string, string>
        {
            ["filesystem"] = @"
                FILESYSTEM RULES:
                - Always use absolute paths
                - Check if file exists before reading
                - Never write outside /workspace"
        }
    }
};

Note: Manifest-level systemPrompt and MCPServerInstructions both provide persistent instructions. Use the manifest approach for new projects.


Permissions

By default, MCP tools require user permission (requiresPermission: true). This is a safety feature since MCP servers can perform arbitrary operations.

Disable for Trusted Servers

json
{
  "name": "readonly-docs",
  "command": "npx",
  "arguments": ["-y", "@example/docs-server"],
  "requiresPermission": false
}

Only disable for read-only or trusted servers.


Environment Variables

Pass environment variables to MCP servers:

json
{
  "name": "github",
  "command": "npx",
  "arguments": ["-y", "@anthropic/mcp-github"],
  "environment": {
    "GITHUB_TOKEN": "${GITHUB_TOKEN}",
    "GITHUB_ORG": "my-org"
  }
}

Use ${VAR_NAME} syntax to reference system environment variables.


Common MCP Servers

ServerPackageDescription
Filesystem@anthropic/mcp-filesystemRead/write files
GitHub@anthropic/mcp-githubRepository operations
PostgreSQL@anthropic/mcp-postgresDatabase queries
Brave Search@anthropic/mcp-brave-searchWeb search
Memory@anthropic/mcp-memoryPersistent key-value store

Example: Multiple Servers

json
{
  "servers": [
    {
      "name": "filesystem",
      "command": "npx",
      "arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
      "enablecollapsing": true
    },
    {
      "name": "github",
      "command": "npx",
      "arguments": ["-y", "@anthropic/mcp-github"],
      "enablecollapsing": true,
      "environment": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    {
      "name": "search",
      "command": "npx",
      "arguments": ["-y", "@anthropic/mcp-brave-search"],
      "enablecollapsing": false,
      "environment": {
        "BRAVE_API_KEY": "${BRAVE_API_KEY}"
      }
    }
  ]
}

Error Handling

Server Startup Failures

By default, if one server fails to start, the agent continues with others:

csharp
.WithMCP("./MCP.json", options =>
{
    options.FailOnServerError = false;  // Default
})

Set FailOnServerError = true to fail fast if any server fails.

Timeouts

Configure connection timeout:

csharp
.WithMCP("./MCP.json", options =>
{
    options.ConnectionTimeout = TimeSpan.FromSeconds(60);
})

Or per-server in manifest:

json
{
  "name": "slow-server",
  "timeout": 60000
}

Troubleshooting

IssueCauseFix
Server not foundcommand not in PATHUse full path or ensure npx is available
Tools not appearingenabled: falseSet enabled: true
Permission deniedServer needs API keyCheck environment variables
TimeoutServer slow to startIncrease timeout

Debug: Check Loaded Tools

csharp
var agent = await new AgentBuilder()
    .WithMCP("./MCP.json")
    .Build();

// List all tools
foreach (var tool in agent.Tools)
{
    Console.WriteLine($"{tool.Name}: {tool.Description}");
}

Best Practices

  1. Use collapsing for servers with many tools to reduce context clutter.

  2. Set requiresPermission: true for servers that can modify data.

  3. Provide descriptions to help the agent understand what each server does.

  4. Use environment variables for secrets—never hardcode tokens.

  5. Set appropriate timeouts based on server startup time.

  6. Use dual-context instructions: Put critical rules in systemPrompt, additional context in functionResult.

  7. Don't duplicate auto-generated messages in functionResult—they waste tokens.

json
{
  "name": "database",
  "command": "npx",
  "arguments": ["-y", "@example/mcp-postgres"],
  "description": "Query the production database (read-only)",
  "enablecollapsing": true,
  "requiresPermission": true,
  "functionResult": "Connected to: production (read-only)",
  "systemPrompt": "LIMIT all queries to 1000 rows. Never use DELETE or UPDATE.",
  "timeout": 10000,
  "environment": {
    "DATABASE_URL": "${DATABASE_URL}"
  }
}

Released under the MIT License.